package com.dukun.mybatis.handler;

import com.dukun.mybatis.entity.GeoPoint;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.PrecisionModel;
import com.vividsolutions.jts.io.WKBReader;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 自定义映射MySQL中geometry类型到GeoPoint
 *
 * @author wuzhen on 2020/11/17
 */
/*
 * mybatis查询结果集中 mysql的geometry类型映射到GeoPoint对象
 */
@MappedTypes(value = {GeoPoint.class})
public class GeoPointTypeHandler extends BaseTypeHandler<GeoPoint> {

    private WKBReader _wkbReader;
    private int _srid = 0;
    public GeoPointTypeHandler() {
        GeometryFactory _geometryFactory = new GeometryFactory(new PrecisionModel(), _srid);
        _wkbReader = new WKBReader(_geometryFactory);
    }
    public GeoPointTypeHandler(int srid) {
        GeometryFactory _geometryFactory = new GeometryFactory(new PrecisionModel(), srid);
        _wkbReader = new WKBReader(_geometryFactory);
    }

    @Override
    public GeoPoint getNullableResult(ResultSet arg0, String arg1) throws SQLException {
        return fromMysqlWkb(arg0.getBytes(arg1));
    }

    @Override
    public GeoPoint getNullableResult(ResultSet arg0, int arg1) throws SQLException {
        return fromMysqlWkb(arg0.getBytes(arg1));
    }

    @Override
    public GeoPoint getNullableResult(CallableStatement arg0, int arg1) throws SQLException {
        return fromMysqlWkb(arg0.getBytes(arg1));
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, GeoPoint geoPoint, JdbcType jdbcType)
            throws SQLException {
        //插入和修改时设置geometry类型值
        ps.setString(i,geoPoint.toString());
    }

    /*
     * bytes转GeoPoint对象
     */
    private GeoPoint fromMysqlWkb(byte[] bytes) {
        if (bytes == null) {
            return null;
        }
        try {
            byte[] geomBytes = ByteBuffer.allocate(bytes.length - 4).order(ByteOrder.LITTLE_ENDIAN)
                    .put(bytes, 4, bytes.length - 4).array();
            Geometry geometry = _wkbReader.read(geomBytes);
            Point point = (Point) geometry;
            return new GeoPoint(new Double(String.valueOf(point.getX())), new Double(String.valueOf(point.getY())));
        } catch (Exception e) {
        }
        return null;
    }
}

